package web.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.util.StringUtil;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
//import web.handler.VerificationCodeException;
import web.exception.CaptchaException;
import web.mapper.CommonMapper;
import web.utils.AesEncryptUtil;

import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static web.utils.AesEncryptUtil.parsePostRequest;

@Component
public class VerificationCodeFilter extends OncePerRequestFilter {

    @Autowired
    CommonMapper commonMapper;

    @Autowired
    @Qualifier("redisTemplate_15_verfiyCode") // 指定注入redisTemplate15
    private RedisTemplate redisTemplate_15_verfiyCode;

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


//如果不是登录接口，不用判断验证码，直接放行
        if (!"/admin/login".equals(request.getRequestURI())) {
            filterChain.doFilter(request, response);
//如果就是登录接口，进行验证码判断
        }

        else {
            try {
                HttpServletRequest wrappedRequest = new MyHttpServletRequestWrapper(request);
                String type=((HttpServletRequest) request).getMethod().toLowerCase();
                String nos=((HttpServletRequest) request).getHeader("nos");
                String timeForHeader=((HttpServletRequest) request).getHeader("sign");
                String time=((HttpServletRequest) request).getHeader("time");
                //用于接口登录不要用户名和密码不要加密

                if(StringUtil.isNotEmpty(nos)&& nos.equals("1")){
                    String requestUri = request.getRequestURI();
                    Map<String, Object> postParams = parsePostRequest(wrappedRequest);
                    verificationCode1(postParams);

                }
                else {

                    if (StringUtil.isEmpty(timeForHeader)) {
                        throw new CaptchaException("501");
                    }
                    if (!"get".equals(type) && StringUtil.isNotEmpty(timeForHeader)) {
                        String requestUri = request.getRequestURI();
                        Map<String, Object> postParams = parsePostRequest(wrappedRequest);
                        String replayKey = AesEncryptUtil.checkToken(timeForHeader, time, postParams);
                        long l = Long.parseLong(time);
                        // 10分钟 方便测试
                        if (System.currentTimeMillis() - l > TimeUnit.MINUTES.toMillis(10)) {

                            throw new CaptchaException("502");
                        }
                        if (timeForHeader.equals(replayKey)) {
                            if (redisTemplate.hasKey(replayKey)) {
                                // 如果存在 表示重放攻击的
                                //log.info("检测到请求可能是重放攻击，不进行处理");

                                throw new CaptchaException("503");
                            } else {
                                // 如果不存在，将时间戳值作为value放到redis中， 避免redis存储越来越多，可将该记录值设为临时的
                                redisTemplate.opsForValue().set(replayKey, timeForHeader, 1, TimeUnit.MINUTES);

                            }

                        } else {
                            throw new CaptchaException("504");
                        }
                        verificationCode1(postParams);
                    }
                }

                //校验验证码


                //验证码校验通过后，对请求进行放行
                filterChain.doFilter(wrappedRequest, response);

            } catch (Exception e) {
//                System.out.println(e);
//                // 创建未经身份验证的 Authentication 对象
//                Authentication auth = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>());
//                // 设置 Authentication 对象，以指示用户已通过身份验证
//                SecurityContextHolder.getContext().setAuthentication(auth);
                // 抛出 CaptchaException
                throw new CaptchaException(e.toString());
            }
        }
    }

    public void verificationCode (HttpServletRequest httpServletRequest) {
        String body = null;
        try {
            body = httpServletRequest.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = JSON.parseObject(body, new TypeReference<HashMap<String, Object>>(){});

        String aquireCaptch = commonMapper.captchaRequire();
        if("1".equals(aquireCaptch)){
            String serial = map.get("serial").toString();
            String input = map.get("captcha").toString();
            Object o = redisTemplate_15_verfiyCode.opsForValue().get("captcha_" + serial);
            if (!input.equals(o.toString())){
                throw new RuntimeException("验证码校验不通过");
            }
        }
    }

    public void verificationCode1 ( Map<String, Object> postParams) {


        String aquireCaptch = commonMapper.captchaRequire();
        if("1".equals(aquireCaptch)){
            String serial = postParams.get("serial").toString();
            String input = postParams.get("captcha").toString();
            Object o = redisTemplate_15_verfiyCode.opsForValue().get("captcha_" + serial);
            if (!input.equals(o.toString())){
                throw new RuntimeException("验证码校验不通过");
            }
        }
    }

    private static class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private final byte[] body;

        public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            body = IOUtils.toByteArray(request.getInputStream());
        }

        @Override
        public ServletInputStream getInputStream() {
            return new ServletInputStream() {
                private ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
                @Override
                public boolean isFinished() {
                    return inputStream.available() == 0;
                }

                @Override
                public boolean isReady() {
                    return true;
                }

                @Override
                public void setReadListener(ReadListener readListener) {
                    // not implemented
                }

                @Override
                public int read() throws IOException {
                    return inputStream.read();
                }
            };
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
    }


}
